home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1996 #6 / Amiga Plus CD - 1996 - No. 06.iso / multimedia / demos / jongl / j2.c < prev    next >
C/C++ Source or Header  |  1996-05-10  |  44KB  |  1,492 lines

  1. echo ; /*
  2. lc -Lt -m3 j2
  3. del j2.info j2.lnk j2.o
  4. quit
  5.  
  6. Übertragen auf AMIGA von Werni am 28295. Enthält evtl. einige Übertragungs-
  7. fehler durch MS1:
  8.  
  9. Alle Änderungen sind mit WR gekennzeichnet.
  10.  
  11. */
  12.  
  13.  
  14.  
  15. /************************************************************************/
  16. /*   J2.C                           Jack Boyce, April 1992              */
  17. /*                                                                      */
  18. /*   This version of J2 is for use with Ed Carstens' animation program  */
  19. /*   JugglePro.  It is IBM-specific and will not compile on anything    */
  20. /*   else!                                                              */
  21. /*                                                                      */
  22. /*   New flags added are:  -write <file>     (outputs to disk file)     */
  23. /*                         -noprint          (disables screen printing) */
  24. /*                         -exit             (exits on keystroke)       */
  25. /*                                                                      */
  26. /*   See the documentation files for an explanation of notation and     */
  27. /*   general operation.                                                 */
  28. /************************************************************************/
  29.  
  30.  
  31. #include <stdio.h>
  32. //WR#include <conio.h>
  33.  
  34. #define  ASYNCH_SOLO      0       /* different types of modes */
  35. #define  SYNCH_SOLO       1
  36. #define  ASYNCH_PASSING   2
  37. #define  CUSTOM           3
  38.  
  39. #define  EMPTY            0       /* types of multiplexing filter slots */
  40. #define  THROW            1
  41. #define  LOWER_BOUND      2
  42.  
  43. #define  BUFFER_SIZE      160     /* # of chars. in file input buffer */
  44. #define  CHARS_PER_THROW   20     /* max. # of chars. printed per throw */
  45.  
  46. struct throw {                    /* records throw information */
  47.    int to;                            /* destination hand # */
  48.    int value;                         /* total time ticks aloft */
  49. };
  50.  
  51. struct filter {                   /* multiplexing filter slot entry */
  52.    int type;                          /* type of entry */
  53.    int from;                          /* source hand # */
  54.    int value;                         /* total time ticks aloft */
  55. };
  56.  
  57.  
  58. // WR:
  59. unsigned char letzte_taste, *key=(unsigned char *)0xbfec01;
  60.  
  61. int ***pattern_rhythm, ***pattern_state, **pattern_throwcount;
  62. int ***pattern_holes;
  63. struct throw ***pattern_throw;
  64. struct filter ***pattern_filter;
  65. int hands, max_occupancy = 0;
  66. int **rhythm_repunit, rhythm_period;
  67. int *holdthrow, *person_number, *scratch1, *scratch2, leader_person = 1;
  68. int **ground_state;
  69. int n, l, h, *xarray, *xparray, *iarray, numflag = 0, groundflag = 0;
  70. int fullflag = 1, lameflag = 1, mp_filter = 1, delaytime = 0;
  71. int sequence_flag = 1, printflag = 1, writeflag = 0, exitflag = 1;
  72. int exitcount = 0;                /* counter for keyboard exit */
  73. int mode = ASYNCH_SOLO;           /* default mode */
  74. int people, slot_size;            /* number of people in pattern */
  75. char *starting_seq, *pattern_buffer, *ending_seq;
  76. FILE *writefile;
  77.  
  78. void die();
  79. char *custom_print_throw();
  80. int custom_valid_pattern(), custom_valid_throw();
  81.  
  82.  
  83. int solo_rhythm_repunit[1][1] =           { { 1 } };
  84. int synch_rhythm_repunit[2][2] =          { { 1, 0 },
  85.                         { 1, 0 } };
  86. int asynch_passing_rhythm_repunit[2][1] = { { 1 },
  87.                         { 1 } };
  88.  
  89.  
  90. int **alloc_array(height, width)
  91. int height, width;
  92. {
  93.    int i, **ptr;
  94.  
  95.    if ((ptr = (int **)malloc(height * sizeof(int *))) == 0)
  96.       die();
  97.    for (i = 0; i < height; i++)
  98.       if ((ptr[i] = (int *)malloc(width * sizeof(int))) == 0)
  99.      die();
  100.  
  101.    return (ptr);
  102. }
  103.  
  104.  
  105. /* The following routine initializes stuff for the built-in rhythms. */
  106. /* This involves allocating and initializing arrays.                 */
  107.  
  108. void initialize()
  109. {
  110.    int i, j;
  111.  
  112.    switch (mode) {
  113.       case ASYNCH_SOLO:
  114.      rhythm_repunit = alloc_array(1, 1);
  115.      rhythm_repunit[0][0] = solo_rhythm_repunit[0][0];
  116.      hands = 1;
  117.      rhythm_period = 1;
  118.      people = 1;
  119.      if ((holdthrow = (int *)malloc(sizeof(int))) == 0)
  120.         die();
  121.      holdthrow[0] = 2;
  122.      if ((person_number = (int *)malloc(sizeof(int))) == 0)
  123.         die();
  124.      person_number[0] = 1;
  125.      break;
  126.       case SYNCH_SOLO:
  127.      rhythm_repunit = alloc_array(2, 2);
  128.      for (i = 0; i < 2; i++)
  129.         for (j = 0; j < 2; j++)
  130.            rhythm_repunit[i][j] = synch_rhythm_repunit[i][j];
  131.      hands = 2;
  132.      rhythm_period = 2;
  133.      people = 1;
  134.      if ((holdthrow = (int *)malloc(2 * sizeof(int))) == 0)
  135.     die();
  136.      holdthrow[0] = holdthrow[1] = 2;
  137.      if ((person_number = (int *)malloc(2 * sizeof(int))) == 0)
  138.         die();
  139.      person_number[0] = person_number[1] = 1;
  140.      break;
  141.       case ASYNCH_PASSING:
  142.      rhythm_repunit = alloc_array(2, 1);
  143.      for (i = 0; i < 2; i++)
  144.         rhythm_repunit[i][0] = asynch_passing_rhythm_repunit[i][0];
  145.      hands = 2;
  146.      rhythm_period = 1;
  147.      people = 2;
  148.      if ((holdthrow = (int *)malloc(2 * sizeof(int))) == 0)
  149.         die();
  150.      holdthrow[0] = holdthrow[1] = 2;
  151.      if ((person_number = (int *)malloc(2 * sizeof(int))) == 0)
  152.         die();
  153.      person_number[0] = 1;
  154.      person_number[1] = 2;
  155.      break;
  156.    }
  157. }
  158.  
  159.  
  160. /* This routine reads a custom rhythm file and parses it to get the */
  161. /* relevant information.  If there is an error it prints a message  */
  162. /* and then exits.                                                  */
  163.  
  164. void custom_initialize(custom_file)
  165. char *custom_file;              /* name of file */
  166. {
  167.    int i, j, k, left_delim, right_delim;
  168.    int last_period, last_person, person, hold, second_pass;
  169.    char ch, *file_buffer;
  170.    FILE *fp;
  171.  
  172.    if ((fp = fopen(custom_file, "r")) == NULL) {
  173.       printf("File error: cannot open '%s'\n", custom_file);
  174.       exit(0);
  175.    }
  176.    if ((file_buffer = (char *)malloc(BUFFER_SIZE * sizeof(char))) == 0)
  177.       die();
  178.  
  179.    for (second_pass = 0; second_pass < 2; second_pass++) {
  180.       hands = j = 0;
  181.       people = last_person = 1;
  182.  
  183.       do {
  184.      ch = (char)(i = fgetc(fp));
  185.  
  186.      if ((ch == (char)10) || (i == EOF)) {
  187.         file_buffer[j] = (char)0;
  188.  
  189.         for (j = 0, k = 0; (ch = file_buffer[j]) && (ch != ';'); j++)
  190.         if (ch == '|') {
  191.            if (++k == 1)
  192.               left_delim = j;
  193.            else if (k == 2)
  194.               right_delim = j;
  195.         }
  196.         if (ch == ';')
  197.            file_buffer[j] = (char)0;        /* terminate at comment */
  198.  
  199.         if (k) {
  200.            if (k != 2) {
  201.          printf("File error: need two rhythm delimiters per hand\n");
  202.           exit(0);
  203.            }
  204.               /* At this point the line checks out.  See if */
  205.               /* period is what we got last time.           */
  206.            if (hands && ((right_delim-left_delim-1) != last_period)) {
  207.           printf("File error: rhythm period not constant\n");
  208.           exit(0);
  209.            }
  210.            last_period = right_delim - left_delim - 1;
  211.  
  212.               /* Now parse the line we've read in */
  213.  
  214.            file_buffer[left_delim] = (char)0;
  215.            person = atoi(file_buffer);
  216.  
  217.            if (hands) {
  218.           if (person == (last_person + 1)) {
  219.              people++;
  220.              last_person = person;
  221.           } else if (person != last_person) {
  222.              printf("File error: person numbers goofed up\n");
  223.              exit(0);
  224.           }
  225.            } else if (person != 1) {
  226.           printf("File error: must start with person number 1\n");
  227.           exit(0);
  228.            }
  229.  
  230.               /* Now put stuff in the allocated arrays */
  231.  
  232.            if (second_pass) {
  233.           person_number[hands] = person;
  234.           hold = atoi(file_buffer + right_delim + 1);
  235.           holdthrow[hands] = (hold ? hold : 2);
  236.  
  237.               /* Fill the rhythm matrix */
  238.           for (j = 0; j < rhythm_period; j++) {
  239.              ch = file_buffer[j + left_delim + 1];
  240.              if (((ch < '0') || (ch > '9')) && (ch != ' ')) {
  241.             printf("File error: bad character in rhythm\n");
  242.             exit(0);
  243.              }
  244.              if (ch == ' ')
  245.             ch = '0';
  246.              rhythm_repunit[hands][j] = (int)(ch - '0');
  247.           }
  248.            }
  249.  
  250.            hands++;   /* got valid line, increment counter */
  251.         }
  252.         j = 0;    /* reset buffer pointer for next read */
  253.      } else {
  254.         file_buffer[j] = ch;
  255.         if (++j >= BUFFER_SIZE) {
  256.            printf("File error: input buffer overflow\n");
  257.            exit(0);
  258.         }
  259.      }
  260.       } while (i != EOF);
  261.  
  262.       if (!hands) {
  263.      printf("File error: must have at least one hand\n");
  264.      exit(0);
  265.       }
  266.  
  267.       if (!second_pass) {        /* allocate space after first pass */
  268.      rhythm_period = last_period;
  269.      rhythm_repunit = alloc_array(hands, rhythm_period);
  270.      if ((holdthrow = (int *)malloc(hands * sizeof(int))) == 0)
  271.         die();
  272.      if ((person_number = (int *)malloc(hands * sizeof(int))) == 0)
  273.         die();
  274.      rewind(fp);          /* go back to start of file */
  275.       }
  276.  
  277.    }
  278.  
  279.    (void)fclose(fp);        /* close file and free memory */
  280.    free(file_buffer);
  281. }
  282.  
  283.  
  284. /*  valid_throw -- checks if a given throw is valid.  Check for        */
  285. /*                 excluded throws and a passing communication delay,  */
  286. /*                 as well a custom filter (if in CUSTOM mode).        */
  287.  
  288. int valid_throw(pos)            /*  1 = valid throw, 0 = invalid  */
  289. int pos;
  290. {
  291.    int i, j, k, balls_left, balls_thrown;
  292.  
  293.    for (i = 0; i < hands; i++) {            /* check for excluded throws */
  294.       if (pattern_rhythm[pos][i][0]) {      /* can we make a throw here? */
  295.      for (j = 0; (j < max_occupancy) &&
  296.                 (k = pattern_throw[pos][i][j].value); j++) {
  297.         if ((people > 1) && (person_number[i] !=
  298.                 person_number[pattern_throw[pos][i][j].to])) {
  299.            if (xparray[k])
  300.           return (0);
  301.         } else if (xarray[k])
  302.            return (0);
  303.      }
  304.      if (!j && xarray[0])
  305.         return (0);
  306.       }
  307.    }
  308.       /*  Now check if we are allowing for a sufficient  */
  309.       /*  communication delay, if we are passing.        */
  310.  
  311.    if ((people > 1) && (pos < delaytime)) {      /* need to check? */
  312.         /*  First count the number of balls being thrown,       */
  313.         /*  assuming no multiplexing.  Also check if leader is  */
  314.         /*  forcing others to multiplex or make no throw.       */
  315.       for (balls_thrown = 0, i = 0; i < hands; i++)
  316.      if (pattern_rhythm[pos][i][0]) {
  317.         balls_thrown++;
  318.         if ((pattern_state[pos][i][0] != 1) &&
  319.                (person_number[i] != leader_person))
  320.            return(0);
  321.      }
  322.  
  323.       balls_left = n;
  324.       for (i = 0; (i < h) && balls_left; i++)
  325.      for (j = 0; (j < hands) && balls_left; j++)
  326.         if (pattern_rhythm[pos + 1][j][i])
  327.            if (--balls_left < balls_thrown) {
  328.           scratch1[balls_left] = j;       /* dest hand # */
  329.           scratch2[balls_left] = i + 1;   /* dest value */
  330.            }
  331.  
  332.       if (balls_left)
  333.      return (0);       /* this shouldn't happen, but die anyway */
  334.  
  335.       for (i = 0; i < hands; i++)
  336.      if (pattern_state[pos][i][0] &&
  337.                 (person_number[i] != leader_person)) {
  338.         for (j = 0, k = 1; (j < balls_thrown) && k; j++)
  339.            if ((scratch1[j] == pattern_throw[pos][i][0].to) &&
  340.                (scratch2[j] == pattern_throw[pos][i][0].value))
  341.           scratch2[j] = k = 0;    /* can't throw to spot again */
  342.         if (k)
  343.            return (0);        /* wasn't throwing to empty position */
  344.      }
  345.    }
  346.  
  347.    if (mode == CUSTOM)
  348.       return (custom_valid_throw(pos));
  349.  
  350.        /****************************************************/
  351.        /*  If you want to add extra throw filters for the  */
  352.        /*  built-in modes, do it here.                     */
  353.        /****************************************************/
  354.  
  355.    return (1);
  356. }
  357.  
  358.  
  359. int valid_pattern()      /*  1 = valid pattern, 0 = invalid  */
  360. {
  361.    int i, j, k, m, q, flag;
  362.  
  363.    for (i = 0; i <= h; i++) {        /* check for included throws */
  364.       if (iarray[i]) {
  365.          flag = 1;
  366.          for (j = 0; (j < l) && flag; j++) {
  367.             for (k = 0; (k < hands) && flag; k++) {
  368.                if (pattern_rhythm[j][k][0]) {
  369.                   m = 0;
  370.                   do {
  371.                      q = pattern_throw[j][k][m].value;
  372.                      if ((q == i) && (k == pattern_throw[j][k][m].to))
  373.                         flag = 0;
  374.              m++;
  375.           } while ((m < max_occupancy) && q && flag);
  376.            }
  377.         }
  378.      }
  379.          if (flag)
  380.             return (0);
  381.       }
  382.    }
  383.  
  384.    if (mode == CUSTOM)
  385.       return (custom_valid_pattern());
  386.    if ((mode == ASYNCH_SOLO) && lameflag && (max_occupancy == 1)) {
  387.       for (i = 0; i < (l - 1); i++)       /* check for '11' sequence */
  388.      if ((pattern_throw[i][0][0].value == 1) &&
  389.               (pattern_throw[i+1][0][0].value == 1))
  390.         return (0);
  391.    }
  392.  
  393.       /********************************************************/
  394.       /*  If you want to add an extra pattern filter for one  */
  395.       /*  of the built-in modes, do it here.                  */
  396.       /********************************************************/
  397.  
  398.    return (1);
  399. }
  400.  
  401.  
  402. char *print_number(pos, value)     /* prints number as single character */
  403. char *pos;
  404. int value;
  405. {
  406.    if (value < 10)
  407.       *pos = (char)value + '0';
  408.    else
  409.       *pos = (char)(value - 10) + 'A';
  410.  
  411.    return (++pos);
  412. }
  413.  
  414.  
  415. char *print_throw(pos, throw, rhythm)  /* prints single throw */
  416. char *pos;
  417. struct throw **throw;
  418. int **rhythm;
  419. {
  420.    int i, j;
  421.  
  422.    for (i = 0, j = 1; (i < hands) && j; i++)
  423.       if (rhythm[i][0])           /* supposed to make a throw? */
  424.      j = 0;
  425.    if (j)
  426.       return (pos);      /* can't make a throw, skip out */
  427.  
  428.    switch (mode) {
  429.       case ASYNCH_SOLO:
  430.      if ((max_occupancy > 1) && throw[0][1].value) {
  431.         *pos++ = '[';
  432.         for (i = 0; (i < max_occupancy) &&
  433.                      (j = throw[0][i].value); i++)
  434.            pos = print_number(pos, j);
  435.         *pos++ = ']';
  436.          } else
  437.         pos = print_number(pos, throw[0][0].value);
  438.      break;
  439.       case SYNCH_SOLO:
  440.      *pos++ = '(';
  441.      if ((max_occupancy > 1) && throw[0][1].value) {
  442.         *pos++ = '[';
  443.         for (i = 0; (i<max_occupancy) && (j=throw[0][i].value); i++) {
  444.            pos = print_number(pos, j);
  445.            if (throw[0][i].to)
  446.           *pos++ = 'x';
  447.         }
  448.         *pos++ = ']';
  449.      } else {
  450.         pos = print_number(pos, throw[0][0].value);
  451.         if (throw[0][0].to)
  452.            *pos++ = 'x';
  453.      }
  454.      *pos++ = ',';
  455.      if ((max_occupancy > 1) && throw[1][1].value) {
  456.         *pos++ = '[';
  457.         for (i = 0; (i<max_occupancy) && (j=throw[1][i].value); i++) {
  458.            pos = print_number(pos, j);
  459.            if (!throw[1][i].to)
  460.           *pos++ = 'x';
  461.         }
  462.         *pos++ = ']';
  463.      } else {
  464.         pos = print_number(pos, throw[1][0].value);
  465.         if (!throw[1][0].to)
  466.            *pos++ = 'x';
  467.      }
  468.      *pos++ = ')';
  469.      break;
  470.       case ASYNCH_PASSING:
  471.      *pos++ = '<';
  472.      if ((max_occupancy > 1) && throw[0][1].value) {
  473.         *pos++ = '[';
  474.         for (i = 0; (i<max_occupancy) && (j=throw[0][i].value); i++) {
  475.            pos = print_number(pos, j);
  476.            if (throw[0][i].to)
  477.           *pos++ = 'p';
  478.         }
  479.         *pos++ = ']';
  480.      } else {
  481.         pos = print_number(pos, throw[0][0].value);
  482.         if (throw[0][0].to)
  483.            *pos++ = 'p';
  484.      }
  485.      *pos++ = '|';
  486.      if ((max_occupancy > 1) && throw[1][1].value) {
  487.         *pos++ = '[';
  488.         for (i = 0; (i<max_occupancy) && (j=throw[1][i].value); i++) {
  489.            pos = print_number(pos, j);
  490.            if (!throw[1][i].to)
  491.           *pos++ = 'p';
  492.         }
  493.         *pos++ = ']';
  494.      } else {
  495.         pos = print_number(pos, throw[1][0].value);
  496.         if (!throw[1][0].to)
  497.            *pos++ = 'p';
  498.      }
  499.      *pos++ = '>';
  500.      break;
  501.       case CUSTOM:
  502.      pos = custom_print_throw(pos, throw, rhythm);
  503.      break;
  504.    }
  505.  
  506.    return (pos);
  507. }
  508.  
  509.  
  510. /*  The following is the default routine that is used to print a  */
  511. /*  throw when the program is in CUSTOM mode.                     */
  512.  
  513. char *default_custom_print_throw(pos, throw, rhythm)
  514. char *pos;
  515. struct throw **throw;
  516. int **rhythm;
  517. {
  518.    int i, j, k, m, q, lo_hand, hi_hand, multiplex, parens;
  519.    char ch;
  520.  
  521.    if (people > 1)
  522.       *pos++ = '<';
  523.  
  524.    for (i = 1; i <= people; i++) {
  525.  
  526.        /* first find the hand numbers corresponding to person */
  527.       for (lo_hand = 0; person_number[lo_hand] != i; lo_hand++)
  528.      ;
  529.       for (hi_hand = lo_hand; (hi_hand < hands) &&
  530.              (person_number[hi_hand] == i); hi_hand++)
  531.      ;
  532.  
  533.        /* check rhythm to see if person is throwing this time */
  534.       for (j = lo_hand, k = 0; j < hi_hand; j++)
  535.      if (rhythm[j][0])
  536.         k++;
  537.  
  538.       if (k) {        /* person should throw */
  539.      if (k > 1) {     /* more than one hand throwing? */
  540.         *pos++ = '(';
  541.         parens = 1;
  542.      } else
  543.         parens = 0;
  544.  
  545.      for (j = lo_hand; j < hi_hand; j++) {
  546.         if (rhythm[j][0]) {      /* this hand supposed to throw? */
  547.            if ((max_occupancy > 1) && throw[j][1].value) {
  548.           *pos++ = '[';        /* multiplexing? */
  549.           multiplex = 1;
  550.            } else
  551.           multiplex = 0;
  552.  
  553.           /* Now loop thru the throws coming out of this hand */
  554.  
  555.            for (k = 0; (k < max_occupancy) &&
  556.                      (m = throw[j][k].value); k++) {
  557.           pos = print_number(pos, m);    /* print throw value */
  558.  
  559.           if (hands > 1) {    /* ambiguity about destination? */
  560.              if ((m = person_number[throw[j][k].to]) != i) {
  561.             *pos++ = ':';
  562.                         pos = print_number(pos, m);
  563.              }
  564.                                         /* person number */
  565.  
  566.              for (q = throw[j][k].to - 1, ch = 'a'; (q >= 0) &&
  567.                   (person_number[q] == m); q--, ch++)
  568.             ;        /* find hand # of destination person */
  569.  
  570.             /* destination person has 1 hand, don't print */
  571.              if ((ch != 'a') || ((q < (hands - 2)) &&
  572.                        (person_number[q + 2] == m)))
  573.             *pos++ = ch;             /* print it */
  574.           }
  575.  
  576.           if (multiplex && (people > 1) &&
  577.             (k != (max_occupancy - 1)) && throw[j][k + 1].value)
  578.              *pos++ = '/';
  579.                                    /* another multiplexed throw? */
  580.            }
  581.            if (k == 0)
  582.           *pos++ = '0';
  583.  
  584.            if (multiplex)
  585.           *pos++ = ']';
  586.         }
  587.  
  588.         if ((j < (hi_hand - 1)) && parens)  /* put comma between hands */
  589.           *pos++ = ',';
  590.      }
  591.      if (parens)
  592.         *pos++ = ')';
  593.       }
  594.  
  595.       if (i < people)           /* another person throwing next? */
  596.      *pos++ = '|';
  597.    }
  598.  
  599.    if (people > 1)
  600.       *pos++ = '>';
  601.  
  602.    return (pos);
  603. }
  604.  
  605.  
  606. void print_pattern()
  607. {
  608.    int i, j, excited = 0, skip;
  609.    char *pos;
  610.  
  611.    if (groundflag != 1) {
  612.       if (sequence_flag) {
  613.      if (mode == ASYNCH_SOLO)
  614.         for (i = n - strlen(starting_seq); i > 0; i--) {
  615.            if (printflag) printf(" ");
  616.            if (writeflag) fprintf(writefile, " ");
  617.         }
  618.      if (printflag) printf("%s  ", starting_seq);
  619.      if (writeflag) fprintf(writefile, "%s ", starting_seq);
  620.       } else {
  621.      excited = compare_states(ground_state, pattern_state[0]);
  622.      if (excited) {
  623.         if (printflag) printf("* ");
  624.         if (writeflag) fprintf(writefile, "* ");
  625.      } else {
  626.         if (printflag) printf("  ");
  627.         if (writeflag) fprintf(writefile, "  ");
  628.      }
  629.       }
  630.    }
  631.  
  632.    pos = pattern_buffer;
  633.    for (i = 0; i < l; i++)
  634.       pos = print_throw(pos, pattern_throw[i], pattern_rhythm[i]);
  635.    *pos = (char)0;         /* terminate the string */
  636.    if (printflag) printf("%s", pattern_buffer);
  637.    if (writeflag) fprintf(writefile, "%s", pattern_buffer);
  638.  
  639.    if (sequence_flag && (groundflag != 1)) {
  640.       if (printflag) printf("  %s\n", ending_seq);
  641.       if (writeflag) fprintf(writefile, "  %s\n", ending_seq);
  642.    } else {
  643.       if (excited) {
  644.      if (printflag) printf(" *\n", ending_seq);
  645.      if (writeflag) fprintf(writefile, " *\n", ending_seq);
  646.       } else {
  647.      if (printflag) printf("\n");
  648.      if (writeflag) fprintf(writefile, "\n");
  649.       }
  650.    }
  651. }
  652.  
  653.  
  654. /*  compare_states -- equality (0), lesser (-1), or greater (1)     */
  655.  
  656. int compare_states(state1, state2)
  657. int **state1, **state2;
  658. {
  659.    int i, j, mo1 = 0, mo2 = 0;
  660.  
  661.    for (i = 0; i < hands; i++)
  662.       for (j = 0; j < h; j++) {
  663.      if (state1[i][j] > mo1)
  664.         mo1 = state1[i][j];
  665.      if (state2[i][j] > mo2)
  666.         mo2 = state2[i][j];
  667.       }
  668.  
  669.    if (mo1 > mo2)
  670.       return (1);
  671.    if (mo1 < mo2)
  672.       return (-1);
  673.  
  674.    for (j = (h - 1); j >= 0; j--)
  675.       for (i = (hands - 1); i >= 0; i--) {
  676.      mo1 = state1[i][j];
  677.      mo2 = state2[i][j];
  678.      if (mo1 > mo2)
  679.         return (1);
  680.      if (mo1 < mo2)
  681.         return (-1);
  682.       }
  683.  
  684.    return (0);
  685. }
  686.  
  687.  
  688.    /*  The next function is part of the implementation of the   */
  689.    /*  multiplexing filter.  It adds a throw to a filter slot,  */
  690.    /*  returning 1 if there is a collision, 0 otherwise.        */
  691.  
  692. int mp_addthrow(dest_slot, slot_hand, type, value, from)
  693. struct filter *dest_slot;
  694. int slot_hand, type, value, from;
  695. {
  696.    switch (type) {
  697.       case EMPTY:
  698.      return (0);
  699.      break;
  700.       case LOWER_BOUND:
  701.      if (dest_slot->type == EMPTY) {
  702.         dest_slot->type = LOWER_BOUND;
  703.         dest_slot->value = value;
  704.         dest_slot->from = from;
  705.         return (0);
  706.      }
  707.      return (0);
  708.      break;
  709.       case THROW:
  710.      if ((from == slot_hand) && (value == holdthrow[slot_hand]))
  711.         return (0);           /* throw is a hold, so ignore it */
  712.  
  713.      switch (dest_slot->type) {
  714.         case EMPTY:
  715.            dest_slot->type = THROW;
  716.            dest_slot->value = value;
  717.            dest_slot->from = from;
  718.            return (0);
  719.            break;
  720.         case LOWER_BOUND:
  721.            if ((dest_slot->value <= value) || (dest_slot->value <=
  722.                   holdthrow[slot_hand])) {
  723.           dest_slot->type = THROW;
  724.           dest_slot->value = value;
  725.           dest_slot->from = from;
  726.           return (0);
  727.            }
  728.            break;       /* this kills recursion */
  729.         case THROW:
  730.            if ((dest_slot->from == from) &&
  731.                (dest_slot->value == value))
  732.           return (0);        /* throws from same place (clump) */
  733.            break;       /* kills recursion */
  734.      }
  735.      break;
  736.    }
  737.  
  738.    return (1);
  739. }
  740.  
  741.  
  742. /*  gen_loops -- This recursively generates loops, given a particular   */
  743. /*               starting state.                                        */
  744.  
  745. unsigned long gen_loops(pos, throws_made, min_throw, min_hand, num)
  746. int pos;              /* slot number in pattern that we're constructing */
  747. int throws_made;      /* number of throws made out of current slot      */
  748. int min_throw;        /* lowest we can throw this time                  */
  749. int min_hand;         /* lowest hand we can throw to this time          */
  750. unsigned long num;    /* number of valid patterns counted               */
  751. {
  752.    int i, j, k, m;
  753.  
  754.    if (exitflag && (exitcount++ == 100)) {   /* kbhit() is slow, so count */
  755.       if (kbhit()) {
  756.      if (writeflag) fclose(writefile);
  757.      while (kbhit())
  758.         (void)getchar(); /* empty input buffer  --WR: getchar() statt getch() */
  759.      exit(0);
  760.       } else
  761.      exitcount = 0;
  762.    }
  763.  
  764.    if (pos == l) {
  765.       if ((compare_states(pattern_state[0], pattern_state[l]) == 0) &&
  766.                 valid_pattern()) {
  767.      if (numflag != 2)
  768.         print_pattern();
  769.      num++;
  770.       }
  771.       return (num);
  772.    }
  773.  
  774.    if (!throws_made)
  775.       for (i = 0; i < hands; i++) {
  776.      pattern_throwcount[pos][i] = pattern_state[pos][i][0];
  777.      for (j = 0; j < h; j++) {
  778.         pattern_holes[pos][i][j] = pattern_rhythm[pos + 1][i][j];
  779.         if (j != (h - 1))
  780.            pattern_holes[pos][i][j] -= pattern_state[pos][i][j + 1];
  781.      }
  782.      for (j = 0; j < max_occupancy; j++) {
  783.         pattern_throw[pos][i][j].to = i;      /* clear throw matrix */
  784.         pattern_throw[pos][i][j].value = 0;
  785.      }
  786.       }
  787.  
  788.    for (i = 0; (i < hands) && (pattern_throwcount[pos][i] == 0); i++)
  789.       ;
  790.  
  791.    if (i == hands) {  /* done with current slot, move to next */
  792.       if (!valid_throw(pos))              /* is the throw ok? */
  793.      return (num);
  794.  
  795.        /* first calculate the next state in ptrn, given last throw */
  796.       for (j = 0; j < hands; j++)      /* shift state to the left */
  797.      for (k = 0; k < h; k++)
  798.         pattern_state[pos + 1][j][k] =
  799.                ( (k == (h-1)) ? 0 : pattern_state[pos][j][k+1] );
  800.  
  801.           /* add on the last throw */
  802.       for (j = 0; j < hands; j++)
  803.      for (k = 0; (k < max_occupancy) &&
  804.                   (m = pattern_throw[pos][j][k].value); k++)
  805.         pattern_state[pos + 1][pattern_throw[pos][j][k].to][m - 1]++;
  806.  
  807.       if (((pos + 1) % rhythm_period) == 0) {
  808.          /* can we compare states? (rhythms must be same) */
  809.      j = compare_states(pattern_state[0], pattern_state[pos + 1]);
  810.      if (fullflag && (pos != (l - 1)) && (j == 0))  /* intersection */
  811.         return (num);
  812.      if (j == 1)       /* prevents cyclic perms. from being printed */
  813.         return (num);
  814.       }
  815.  
  816.       if (fullflag == 2) {            /* list only simple loops? */
  817.          for (j = 1; j <= pos; j++)
  818.             if (((pos + 1 - j) % rhythm_period) == 0) {
  819.                if (compare_states(pattern_state[j],
  820.                          pattern_state[pos + 1]) == 0)
  821.           return (num);
  822.         }
  823.       }
  824.  
  825.       /*  Now do the multiplexing filter.  This ensures that,  */
  826.       /*  other than holds, objects from only one source are   */
  827.       /*  landing in any given hand (for example, a clump of   */
  828.       /*  3's).  The implementation is a little complicated,   */
  829.       /*  since I want to cut off the recursion as quickly as  */
  830.       /*  possible to get speed on big searches.  This         */
  831.       /*  precludes simply generating all patterns and then    */
  832.       /*  throwing out the unwanted ones.                      */
  833.  
  834.       if (mp_filter) {
  835.      for (j = 0; j < hands; j++) {    /* shift filter frame to left */
  836.         for (k = 0; k < (slot_size - 1); k++) {
  837.            pattern_filter[pos + 1][j][k].type =
  838.                   pattern_filter[pos][j][k + 1].type;
  839.            pattern_filter[pos + 1][j][k].from =
  840.                   pattern_filter[pos][j][k + 1].from;
  841.            pattern_filter[pos + 1][j][k].value =
  842.                   pattern_filter[pos][j][k + 1].value;
  843.         }
  844.         pattern_filter[pos + 1][j][slot_size - 1].type = EMPTY;
  845.                   /* empty slots shift in */
  846.  
  847.         if (mp_addthrow( &(pattern_filter[pos + 1][j][l - 1]),
  848.               j, pattern_filter[pos][j][0].type,
  849.               pattern_filter[pos][j][0].value,
  850.               pattern_filter[pos][j][0].from))
  851.            return (num);
  852.      }
  853.  
  854.      for (j = 0; j < hands; j++)           /* add on last throw */
  855.         for (k = 0; (k < max_occupancy) &&
  856.                    (m = pattern_throw[pos][j][k].value); k++)
  857.            if (mp_addthrow( &(pattern_filter[pos + 1]
  858.               [pattern_throw[pos][j][k].to][m - 1]),
  859.                pattern_throw[pos][j][k].to, THROW, m, j))
  860.           return (num);        /* problem, so end recursion */
  861.       }
  862.  
  863.       num = gen_loops(pos + 1, 0, 1, 0, num);       /* go to next slot */
  864.    } else {
  865.       m = --pattern_throwcount[pos][i];     /* record throw */
  866.       k = min_hand;
  867.  
  868.       for (j = min_throw; j <= h; j++) {
  869.      for ( ; k < hands; k++) {
  870.         if (pattern_holes[pos][k][j - 1]) {/*can we throw to position?*/
  871.            pattern_holes[pos][k][j - 1]--;
  872.            pattern_throw[pos][i][m].to = k;
  873.            pattern_throw[pos][i][m].value = j;
  874.            if (m)
  875.           num = gen_loops(pos, throws_made + 1, j, k, num);
  876.            else
  877.           num = gen_loops(pos, throws_made + 1, 1, 0, num);
  878.            pattern_holes[pos][k][j - 1]++;
  879.         }
  880.      }
  881.      k = 0;
  882.       }
  883.       pattern_throwcount[pos][i]++;
  884.    }
  885.  
  886.    return (num);
  887. }
  888.  
  889.  
  890. /*  The next routine finds valid starting and ending sequences for      */
  891. /*  excited state patterns.  Note that these sequences are not unique.  */
  892.  
  893. void find_start_end()
  894. {
  895.    int i, j, k, m, q, flag;
  896.    char *pos;
  897.  
  898.    *starting_seq = (char)0;    /* first set to null strings (in case */
  899.    *ending_seq = (char)0;      /* we have a ground state trick)      */
  900.  
  901.               /* first find the starting sequence */
  902.    i = slot_size;       /* throw position to start at (work back to gnd) */
  903.    for (j = 0; j < hands; j++)
  904.       for (k = 0; k < h; k++)
  905.      pattern_state[i][j][k] = pattern_state[0][j][k];   /* copy state */
  906.  
  907.    while ((i % rhythm_period) || compare_states(pattern_state[i],
  908.                           ground_state)) {
  909.       m = h;            /* pointers to current ball we're pulling down */
  910.       q = hands - 1;
  911.  
  912.       for (j = hands - 1; j >= 0; j--) {
  913.      for (k = 0; k < max_occupancy; k++) {     /* clear throw matrix */
  914.         pattern_throw[i - 1][j][k].value = 0;
  915.         pattern_throw[i - 1][j][k].to = j;
  916.      }
  917.  
  918.      pattern_state[i - 1][j][0] = 0;
  919.      if (pattern_rhythm[i - 1][j][0]) {
  920.         while (pattern_state[i][q][m - 1] == 0) {
  921.            if (q-- == 0) {     /* go to next position to pull down */
  922.           q = hands - 1;
  923.           if (!(--m))
  924.              goto skip1;
  925.            }
  926.         }
  927.         pattern_throw[i - 1][j][0].value = m;
  928.         pattern_throw[i - 1][j][0].to = q;
  929.         pattern_state[i][q][m - 1]--;
  930.         pattern_state[i - 1][j][0]++;
  931.      }
  932.       }
  933.  
  934. skip1:
  935.       for (j = 0; j < hands; j++) {
  936.      if (pattern_state[i][j][h - 1]) {
  937.         *starting_seq = '?';
  938.         starting_seq[1] = (char)0;
  939.         goto skip2;       /* skip to where ending seq. is found */
  940.      }
  941.      for (k = 1; k < h; k++)
  942.         pattern_state[i - 1][j][k] = pattern_state[i][j][k - 1];
  943.       }
  944.  
  945.       i--;
  946.       if ((i == 0) && compare_states(*pattern_state, ground_state)) {
  947.      *starting_seq = '?';
  948.      starting_seq[1] = (char)0;
  949.      goto skip2;
  950.       }
  951.    }
  952.  
  953.    pos = starting_seq;            /* write starting seq. to buffer */
  954.    for ( ; i < slot_size; i++)
  955.       pos = print_throw(pos, pattern_throw[i], pattern_rhythm[i]);
  956.    *pos = (char)0;      /* terminate string */
  957.  
  958.      /*  Now construct an ending sequence.  Unlike the starting  */
  959.      /*  sequence above, this time work forward to ground state. */
  960.  
  961. skip2:
  962.    i = 0;
  963.    while ((i % rhythm_period) || compare_states(pattern_state[i],
  964.                  ground_state)) {
  965.       m = 1;
  966.       q = 0;
  967.       for (j = 0; j < hands; j++) {
  968.      for (k = 0; k < max_occupancy; k++) {
  969.         pattern_throw[i][j][k].value = 0;
  970.         pattern_throw[i][j][k].to = j;
  971.      }
  972.      for (k = pattern_state[i][j][0] - 1; k >= 0; k--) {
  973.         flag = 1;
  974.         while (flag) {
  975.            for ( ; (q < hands) && flag; q++) {
  976.           if (pattern_rhythm[i+1][q][m-1] && ((m >= h) ||
  977.                   (pattern_state[i][q][m] == 0))) {
  978.              if (m > h) {
  979.             *ending_seq = '?';
  980.             ending_seq[1] = (char)0;
  981.             return;          /* no place to put ball */
  982.              }
  983.              pattern_throw[i][j][k].value = m;
  984.              pattern_throw[i][j][k].to = q;
  985.              flag = 0;
  986.           }
  987.            }
  988.            if (q == hands) {
  989.           q = 0;
  990.           m++;
  991.            }
  992.         }
  993.      }
  994.       }
  995.       for (j = 0; j < hands; j++) {       /* shift the state left */
  996.      for (k = 0; k < (h - 1); k++)
  997.         pattern_state[i+1][j][k] = pattern_state[i][j][k+1];
  998.      pattern_state[i+1][j][h-1] = 0;
  999.       }
  1000.       for (j = 0; j < hands; j++)         /* add on the last throws */
  1001.      for (k = 0; (k < max_occupancy) &&
  1002.             (m = pattern_throw[i][j][k].value); k++)
  1003.         pattern_state[i+1][pattern_throw[i][j][k].to][m-1] = 1;
  1004.       if (++i > h) {
  1005.      *ending_seq = '?';
  1006.      ending_seq[1] = (char)0;
  1007.      return;
  1008.       }
  1009.    }
  1010.  
  1011.    pos = ending_seq;            /* write ending seq. to buffer */
  1012.    for (j = 0; j < i; j++)
  1013.       pos = print_throw(pos, pattern_throw[j], pattern_rhythm[j]);
  1014.    *pos = (char)0;           /* terminate starting string */
  1015. }
  1016.  
  1017.  
  1018. /*  gen_patterns -- Recursively generates all possible starting        */
  1019. /*                  states, calling gen_loops above to find the loops  */
  1020. /*                  for each one.                                      */
  1021.  
  1022. unsigned long gen_patterns(balls_placed, min_value, min_to, num)
  1023. int balls_placed, min_value, min_to;
  1024. unsigned long num;
  1025. {
  1026.    int i, j, k, m, q;
  1027.  
  1028.    if ((balls_placed == n) || (groundflag == 1)) {
  1029.       if (groundflag == 1) {    /* find only ground state patterns? */
  1030.      for (i = 0; i < hands; i++)
  1031.         for (j = 0; j < h; j++)
  1032.            pattern_state[0][i][j] = ground_state[i][j];
  1033.       } else if ((groundflag == 2) &&
  1034.              !compare_states(pattern_state[0], ground_state))
  1035.      return(num);         /* don't find ground state patterns */
  1036.  
  1037.        /*  At this point our state is completed.  Check to see      */
  1038.        /*  if it's valid.  (Position X must be at least as large    */
  1039.        /*  as position X+L, where L = pattern length.)  Also set    */
  1040.        /*  up the initial multiplexing filter frame, if we need it. */
  1041.  
  1042.       for (i = 0; i < hands; i++) {
  1043.      for (j = 0; j < h; j++) {
  1044.  
  1045.         k = pattern_state[0][i][j];
  1046.         if (mp_filter && !k)
  1047.            pattern_filter[0][i][j].type = EMPTY;
  1048.         else {
  1049.            if (mp_filter) {
  1050.           pattern_filter[0][i][j].value = j + 1;
  1051.           pattern_filter[0][i][j].from = i;
  1052.           pattern_filter[0][i][j].type = LOWER_BOUND;
  1053.            }
  1054.  
  1055.            m = j;
  1056.            while ((m += l) < h) {
  1057.           if ((q = pattern_state[0][i][m]) > k)
  1058.              return (num);     /* die (invalid state for this L) */
  1059.           if (mp_filter && q) {
  1060.              if ((q < k) && (j > holdthrow[i]))
  1061.             return (num);  /* different throws into same hand */
  1062.              pattern_filter[0][i][j].value = m + 1;  /* new bound */
  1063.           }
  1064.            }
  1065.         }
  1066.      }
  1067.  
  1068.      if (mp_filter)
  1069.         for ( ; j < slot_size; j++)
  1070.            pattern_filter[0][i][j].type = EMPTY; /* clear rest of slot */
  1071.       }
  1072.  
  1073.       if ((numflag != 2) && sequence_flag)
  1074.      find_start_end();/* find starting and ending sequences for state */
  1075.  
  1076.       return (gen_loops(0, 0, 1, 0, num));   /* find patterns thru state */
  1077.    }
  1078.  
  1079.    if (!balls_placed) {        /* startup, clear state */
  1080.       for (i = 0; i < hands; i++)
  1081.      for (j = 0; j < h; j++)
  1082.         pattern_state[0][i][j] = 0;
  1083.    }
  1084.  
  1085.    j = min_to;       /* ensures each state is generated only once */
  1086.    for (i = min_value; i < h; i++) {
  1087.       for ( ; j < hands; j++) {
  1088.      if (pattern_state[0][j][i] < pattern_rhythm[0][j][i]) {
  1089.         pattern_state[0][j][i]++;
  1090.         num = gen_patterns(balls_placed + 1, i, j, num);   /* recursion */
  1091.         pattern_state[0][j][i]--;
  1092.      }
  1093.       }
  1094.       j = 0;
  1095.    }
  1096.  
  1097.    return (num);
  1098. }
  1099.  
  1100.  
  1101. /*  find_ground -- Find the ground state for our rhythm.  Just put  */
  1102. /*                 the balls in the lowest possible slots, with no  */
  1103. /*                 multiplexing.                                    */
  1104.  
  1105. void find_ground()
  1106. {
  1107.    int i, j, balls_left;
  1108.  
  1109.    balls_left = n;
  1110.  
  1111.    for (i = 0; i < hands; i++)       /* clear ground state array */
  1112.       for (j = 0; j < h; j++)
  1113.      ground_state[i][j] = 0;
  1114.  
  1115.    for (i = 0; (i < h) && balls_left; i++)
  1116.       for (j = 0; (j < hands) && balls_left; j++)
  1117.      if (pattern_rhythm[0][j][i]) {      /* available slots */
  1118.         ground_state[j][i] = 1;
  1119.         balls_left--;
  1120.      }
  1121.  
  1122.    if (balls_left) {
  1123.       printf("Maximum throw value is too small\n");
  1124.       exit(0);
  1125.    }
  1126. }
  1127.  
  1128.  
  1129.  
  1130. /*  This is the entry point of the program.  It decodes the command  */
  1131. /*  line, allocates the necessary memory space, and then calls       */
  1132. /*  gen_patterns above to find the loops.                            */
  1133.  
  1134. void main(argc, argv)
  1135. int argc;
  1136. char **argv;
  1137. {
  1138.    int i, j, k, multiplex = 1;
  1139.    unsigned long num;
  1140.  
  1141.    if (argc < 4) {
  1142.       printf(
  1143. "USAGE: j2 <number of objects> <max. throw> <pattern length> [-options]\n");
  1144.       printf(
  1145. "                 by Jack Boyce (jboyce@tybalt.caltech.edu)\n\n");
  1146.       printf(
  1147. "This program finds juggling patterns in a generalized form of site swap\n");
  1148.       printf(
  1149. "notation.  For a full description of this notation and the program's\n");
  1150.       printf(
  1151. "operation, consult the accompanying documentation files.  All patterns\n");
  1152.       printf(
  1153. "satisfying the given constraints are listed by the program.  Solo asynch-\n");
  1154.       printf(
  1155. "ronous juggling is the default mode.  This AMIGA-version was ported from\n");
  1156.       printf(
  1157. "MS-DOS by Werner Riebesel, Auenbruggerstr. 110, D-80999 München.\n\n");
  1158.       printf("Command line options:\n");
  1159.       printf(
  1160. " -s  solo synchronous mode     -m <number>  multiplexing with at most the\n");
  1161.       printf(
  1162. " -p  2 person passing mode          given number of simultaneous throws\n");
  1163.       printf(
  1164. " -c <file>  custom mode        -mf  turn off multiplexing filter\n");
  1165.       printf(
  1166. " -n  show number of patterns   -d <number>  passing communication delay\n");
  1167.       printf(
  1168. " -no print number only         -l <number>  passing leader person number\n");
  1169.       printf(
  1170. " -g  ground state patterns     -x <throw> ..  exclude listed self-throws\n");
  1171.       printf(
  1172. " -ng excited state patterns    -xp <throw> .. exclude listed passes\n");
  1173.       printf(
  1174. " -f  full listing (decompos-   -i <throw> ..  must include listed self-\n");
  1175.       printf(
  1176. "     able patterns too)             throws\n");
  1177.       printf(
  1178. " -se disable starting/ending   -lame  allow '11' seq. in solo asynch mode\n");
  1179.       printf(
  1180. " -simple  list only non-decomposable patterns\n");
  1181.       printf(
  1182. " -noprint  disables printing   -write <file>  outputs to disk file\n");
  1183.       printf(
  1184. " -noexit  disables keystroke exit\n");
  1185.       exit(0);
  1186.    }
  1187.  
  1188.    n = atoi(argv[1]);                    /* get the number of objects */
  1189.    if (n < 1) {
  1190.       printf("Must have at least 1 object\n");
  1191.       exit(0);
  1192.    }
  1193.    h = atoi(argv[2]);                    /* get the max. throw throw */
  1194.    l = atoi(argv[3]);
  1195.    if (l < 1) {
  1196.       printf("Pattern length must be at least 1\n");
  1197.       exit(0);
  1198.    }
  1199.  
  1200.    if ((xarray = (int *)malloc((h + 1) * sizeof(int))) == 0)
  1201.       die();                 /* excluded self-throws */
  1202.    if ((xparray = (int *)malloc((h + 1) * sizeof(int))) == 0)
  1203.       die();                 /* excluded passes */
  1204.    if ((iarray = (int *)malloc((h + 1) * sizeof(int))) == 0)
  1205.       die();
  1206.    for (i = 0; i <= h; i++) {      /* initialize to default */
  1207.       xarray[i] = 0;
  1208.       xparray[i] = 0;
  1209.       iarray[i] = 0;
  1210.    }
  1211.  
  1212.    for (i = 4; i < argc; i++) {
  1213.       if (!strcmp(argv[i], "-n"))
  1214.      numflag = 1;
  1215.       else if (!strcmp(argv[i], "-no"))
  1216.      numflag = 2;
  1217.       else if (!strcmp(argv[i], "-g"))
  1218.      groundflag = 1;
  1219.       else if (!strcmp(argv[i], "-ng"))
  1220.      groundflag = 2;
  1221.       else if (!strcmp(argv[i], "-f"))
  1222.      fullflag = 0;
  1223.       else if (!strcmp(argv[i], "-simple"))
  1224.      fullflag = 2;
  1225.       else if (!strcmp(argv[i], "-noprint"))
  1226.      printflag = 0;
  1227.       else if (!strcmp(argv[i], "-noexit"))
  1228.      exitflag = 0;
  1229.       else if (!strcmp(argv[i], "-write")) {
  1230.      if (!writeflag) {
  1231.         if (i != (argc - 1)) {
  1232.            writeflag = 1;
  1233.            if ((writefile = fopen(argv[++i], "w")) == 0) {
  1234.           printf("Cannot open disk file\n");
  1235.           exit(0);
  1236.            }
  1237.         } else {
  1238.            printf("No write file name given\n");
  1239.            exit(0);
  1240.         }
  1241.      }
  1242.       }
  1243.       else if (!strcmp(argv[i], "-lame"))
  1244.      lameflag = 0;
  1245.       else if (!strcmp(argv[i], "-se"))
  1246.      sequence_flag = 0;
  1247.       else if (!strcmp(argv[i], "-s"))
  1248.      mode = SYNCH_SOLO;
  1249.       else if (!strcmp(argv[i], "-p"))
  1250.      mode = ASYNCH_PASSING;
  1251.       else if (!strcmp(argv[i], "-c")) {
  1252.      mode = CUSTOM;
  1253.      if (i != (argc - 1))
  1254.         custom_initialize(argv[++i]);
  1255.      else {
  1256.         printf("No custom rhythm file given\n");
  1257.         exit(0);
  1258.      }
  1259.       } else if (!strcmp(argv[i], "-mf"))
  1260.      mp_filter = 0;
  1261.       else if (!strcmp(argv[i], "-m")) {
  1262.      if ((i < (argc - 1)) && (argv[i + 1][0] != '-')) {
  1263.         multiplex = atoi(argv[i + 1]);
  1264.         i++;
  1265.      }
  1266.       }
  1267.       else if (!strcmp(argv[i], "-d")) {
  1268.      if ((i < (argc - 1)) && (argv[i + 1][0] != '-')) {
  1269.         delaytime = atoi(argv[i + 1]);
  1270.         groundflag = 1;        /* find only ground state tricks */
  1271.         i++;
  1272.      }
  1273.       }
  1274.       else if (!strcmp(argv[i], "-l")) {
  1275.      if ((i < (argc - 1)) && (argv[i + 1][0] != '-')) {
  1276.         leader_person = atoi(argv[i + 1]);
  1277.         i++;
  1278.      }
  1279.       }
  1280.       else if (!strcmp(argv[i], "-x") || !strcmp(argv[i], "-xs")) {
  1281.      i++;
  1282.      while ((i < argc) && (argv[i][0] != '-')) {
  1283.         j = atoi(argv[i]);
  1284.         if ((j >= 0) && (j <= h))
  1285.            xarray[j] = 1;
  1286.         i++;
  1287.      }
  1288.      i--;
  1289.       }
  1290.       else if (!strcmp(argv[i], "-xp")) {
  1291.      i++;
  1292.      while ((i < argc) && (argv[i][0] != '-')) {
  1293.         j = atoi(argv[i]);
  1294.         if ((j >= 0) && (j <= h))
  1295.            xparray[j] = 1;
  1296.         i++;
  1297.      }
  1298.      i--;
  1299.       }
  1300.       else if (!strcmp(argv[i], "-i")) {
  1301.      i++;
  1302.      while ((i < argc) && (argv[i][0] != '-')) {
  1303.         j = atoi(argv[i]);
  1304.         if ((j >= 0) && (j <= h))
  1305.            iarray[j] = 1;
  1306.         i++;
  1307.      }
  1308.      i--;
  1309.       } else {
  1310.          printf("Unrecognized command line option '%s'\n", argv[i]);
  1311.          exit(0);
  1312.       }
  1313.    }
  1314.  
  1315.    for (i = 0; i <= h; i++)        /* include and exclude flags clash? */
  1316.       if (iarray[i] && xarray[i])
  1317.          exit(0);
  1318.  
  1319.    if (mode != CUSTOM)
  1320.       initialize();
  1321.  
  1322.    if (l % rhythm_period) {
  1323.       printf("Pattern length must be a multiple of %d\n", rhythm_period);
  1324.       exit(0);
  1325.    }
  1326.  
  1327.        /*  The following variable slot_size serves two functions.  It  */
  1328.        /*  is the size of a slot used in the multiplexing filter, and  */
  1329.        /*  it is the number of throws allocated in memory.  The number */
  1330.        /*  of throws needs to be larger than L sometimes since these   */
  1331.        /*  same structures are used to find starting and ending        */
  1332.        /*  sequences (containing as many as H elements).               */
  1333.  
  1334.    slot_size = ((h > l) ? h : l);
  1335.    slot_size += rhythm_period - (slot_size % rhythm_period);
  1336.  
  1337.    for (i = 0; i < hands; i++)
  1338.       for (j = 0; j < rhythm_period; j++)
  1339.      if ((k = rhythm_repunit[i][j]) > max_occupancy)
  1340.         max_occupancy = k;
  1341.    max_occupancy *= multiplex;
  1342.    if (max_occupancy == 1)       /* no multiplexing, turn off filter */
  1343.       mp_filter = 0;
  1344.  
  1345.      /*  Now allocate the memory space for the states, rhythms, and  */
  1346.      /*  throws in the pattern, plus other incidental variables.     */
  1347.  
  1348.    if ((pattern_state = (int ***)
  1349.            malloc((slot_size + 1) * sizeof(int **))) == 0)
  1350.       die();
  1351.    for (i = 0; i < (slot_size + 1); i++)
  1352.       pattern_state[i] = alloc_array(hands, h);
  1353.  
  1354.    if ((pattern_rhythm = (int ***)
  1355.            malloc((slot_size + 1) * sizeof(int **))) == 0)
  1356.       die();
  1357.    for (i = 0; i < (slot_size + 1); i++) {
  1358.       pattern_rhythm[i] = alloc_array(hands, h);
  1359.       for (j = 0; j < hands; j++)
  1360.      for (k = 0; k < h; k++)
  1361.         pattern_rhythm[i][j][k] =
  1362.          multiplex * rhythm_repunit[j][(k + i) % rhythm_period];
  1363.    }
  1364.  
  1365.    if ((pattern_holes = (int ***)
  1366.            malloc(l * sizeof(int **))) == 0)
  1367.       die();
  1368.    for (i = 0; i < l; i++)
  1369.       pattern_holes[i] = alloc_array(hands, h);
  1370.  
  1371.    if ((pattern_throw = (struct throw ***)
  1372.            malloc(slot_size * sizeof(struct throw **))) == 0)
  1373.       die();
  1374.    for (i = 0; i < slot_size; i++) {
  1375.       if ((pattern_throw[i] = (struct throw **)
  1376.                malloc(hands * sizeof(struct throw *))) == 0)
  1377.      die();
  1378.       for (j = 0; j < hands; j++)
  1379.      if ((pattern_throw[i][j] = (struct throw *)
  1380.            malloc(max_occupancy * sizeof(struct throw))) == 0)
  1381.         die();
  1382.    }
  1383.  
  1384.    if (mp_filter) {         /* allocate space for filter variables */
  1385.       if ((pattern_filter = (struct filter ***)
  1386.           malloc((l + 1) * sizeof(struct filter **))) == 0)
  1387.      die();
  1388.       for (i = 0; i <= l; i++) {
  1389.      if ((pattern_filter[i] = (struct filter **)
  1390.               malloc(hands * sizeof(struct filter *))) == 0)
  1391.         die();
  1392.      for (j = 0; j < hands; j++)
  1393.         if ((pattern_filter[i][j] = (struct filter *)
  1394.               malloc(slot_size * sizeof(struct filter))) == 0)
  1395.            die();
  1396.       }
  1397.    }
  1398.  
  1399.    pattern_throwcount = alloc_array(l, hands);
  1400.    ground_state = alloc_array(hands, h);
  1401.  
  1402.    if (people > 1) {       /* passing communication delay variables */
  1403.       if ((scratch1 = (int *)malloc(hands * sizeof(int))) == 0)
  1404.      die();
  1405.       if ((scratch2 = (int *)malloc(hands * sizeof(int))) == 0)
  1406.      die();
  1407.    }
  1408.  
  1409.    if ((starting_seq=(char *)malloc(hands*h*CHARS_PER_THROW*sizeof(char)))==0)
  1410.       die();
  1411.    if ((ending_seq = (char *)malloc(hands*h*CHARS_PER_THROW*sizeof(char)))==0)
  1412.       die();
  1413.    if ((pattern_buffer = (char *)malloc(hands*l*CHARS_PER_THROW*
  1414.                   sizeof(char)))==0)
  1415.       die();
  1416.  
  1417.        /*  Now that all the storage space is allocated, generate  */
  1418.        /*  and print out the loops.  */
  1419.  
  1420. // WR:
  1421.    letzte_taste=*key;
  1422.  
  1423.  
  1424.    find_ground();                /* find ground state */
  1425.  
  1426.    num = gen_patterns(0, 0, 0, 0L);
  1427.  
  1428.    if (numflag) {
  1429.       if (num == 1) {
  1430.      if (printflag) printf("1 pattern found\n");
  1431.      if (writeflag) fprintf(writefile, "1 pattern found\n");
  1432.       } else {
  1433.      if (printflag) printf("%ld patterns found\n", num);
  1434.      if (writeflag) fprintf(writefile, "%ld patterns found\n", num);
  1435.       }
  1436.    }
  1437.  
  1438.    if (writeflag)
  1439.       fclose(writefile);
  1440.  
  1441.    exit(0);        /* frees memory */
  1442. }
  1443.  
  1444.  
  1445. void die()       /* just like the name sounds */
  1446. {
  1447.    printf("Insufficient memory\n");
  1448.    exit(0);
  1449. }
  1450.  
  1451.  
  1452. /***********************************************************************/
  1453. /*                                                                     */
  1454. /*  The following are the customization functions.                     */
  1455. /*  See the documentation for an explanation of these routines.        */
  1456. /*                                                                     */
  1457. /***********************************************************************/
  1458.  
  1459. int custom_valid_throw(pos)    /* excluded throws already checked for */
  1460. int pos;
  1461. {
  1462.    return (1);           /* return throw ok */
  1463. }
  1464.  
  1465. int custom_valid_pattern()
  1466. {
  1467.    return (1);           /* return pattern ok */
  1468. }
  1469.  
  1470. char *custom_print_throw(pos, throw, rhythm)
  1471. char *pos;                      /* buffer pointer we're writing to */
  1472. struct throw **throw;
  1473. int **rhythm;
  1474. {
  1475.    return (default_custom_print_throw(pos, throw, rhythm));
  1476.                   /* just do the default for now */
  1477. }
  1478.  
  1479. /***********************************************************************/
  1480.  
  1481.  
  1482. /* WR  kbhit() dazugeschrieben: Annahme: gibt !=0 zurück, wenn irgendeine
  1483.        Taste gedrückt wurde. */
  1484.  
  1485. kbhit() {
  1486.    if (*key!=letzte_taste) {
  1487.       letzte_taste=*key;
  1488.       return 1;
  1489.    }
  1490.    else return 0;
  1491. }
  1492.